package com.kcht.np.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kcht.np.common.domain.TreeNode;
import com.kcht.np.common.exception.ParameterException;
import com.kcht.np.common.jwt.JwtTokenConverter;
import com.kcht.np.common.jwt.JwtUser;
import com.kcht.np.constant.InitData;
import com.kcht.np.entity.Relation;
import com.kcht.np.entity.SysPermission;
import com.kcht.np.entity.SysRole;
import com.kcht.np.mapper.SysPermissionMapper;
import com.kcht.np.mapper.SysRoleMapper;
import com.kcht.np.service.SysPermissionService;
import com.kcht.np.service.SysRoleService;
import com.kcht.np.util.TreeNodeUtils;
import com.kcht.np.vo.role.RoleCanCreateInfo;
import com.kcht.np.vo.role.RoleCanModifyInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
  * <p>
  * 角色 Service 接口
  * </p>
  *
  * @Package:        com.kcht.np.mp.service.impl
  * @Description:    角色 Service 接口
  * @Author:         liuqi
  * @CreateDate:     2020/3/31 21:25
 */

@Slf4j
@Service
@DS("kchtnp")
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    @Autowired
    private SysPermissionService permissionService;
    @Autowired
    private SysPermissionMapper permissionMapper;
    @Autowired
    @Lazy
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private JwtTokenConverter jwtTokenConverter;

    private BoundHashOperations<String, String, JwtUser> tokenStorage() {
        return redisTemplate.boundHashOps(jwtTokenConverter.getTokenHeader());
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void grantPermissions(Long rid, Set<Long> permissionIds) {
//        if(InitData.ROOT_ROLE.equals(rid)){
//            throw new ParameterException("不能操作超级管理角色");
//        }
        if(baseMapper.selectById(rid)==null){
            throw new ParameterException("无此角色");
        }
        Set<Long> allPer=new HashSet<>(permissionIds);
        for (Long permissionId : permissionIds) {
            collectParentPer(allPer,permissionId);
        }
        List<Relation> collect = allPer.stream()
                // 去除重复的 权限 ID
                .distinct()
                .filter(pid -> pid != null && pid > 0)
                // 构造 Relation 对象
                .map(res -> new Relation(rid, res))
                .collect(Collectors.toList());
        Set<String> users = baseMapper.usersRefRole(rid);
        users.forEach((username)->{
            tokenStorage().delete(username);
        });
        // 先删除当前角色拥有的所有权限
        baseMapper.deleteHavePermissions(rid);
        // 在赋值新的 权限
        baseMapper.grantPermissions(collect);
    }

    private void collectParentPer(Set<Long> pids,Long pid){
        if(InitData.TOP_PER.equals(pid)){
            return ;
        }
        pids.add(pid);
        SysPermission permission = permissionMapper.selectById(pid);
        if(permission==null){
            throw new ParameterException("没有标识为"+pid+"的权限");
        }
        collectParentPer(pids,permission.getParentId());
    }

    @Override
    public Set<SysRole> findRolesByUserId(Long uid) {
        return baseMapper.findRolesByUserId(uid);
    }

    @Override
    public Map<String, Object> queryRichRole(Long rid) {
        if(baseMapper.selectById(rid)==null){
            throw new ParameterException("无此角色");
        }
        Map<String, Object> map = new HashMap<>(2);
        // 获取当前角色，拥有的权限
        Set<SysPermission> havePermissionCollect = baseMapper.queryPermissionsByRoleId(rid);

        // 获取全部的权限
        List<TreeNode> allPermissionCollect = permissionService.list()
                .stream()
                .distinct()
                .map(res -> new TreeNode(res.getPid(), res.getTitle(), res.getParentId(), null, null))
                .collect(Collectors.toList());

        // 将当前角色拥有的权限 pid，挑选出来
        Set<Long> hashSet = havePermissionCollect.stream().map(SysPermission::getPid).collect(Collectors.toSet());
        // 再次遍历，当前角色拥有的权限，然后 移除父节点 只留下子节点。
        havePermissionCollect.forEach(res -> hashSet.remove(res.getParentId()));
        // 将全部权限，递归成树节点的形式
        map.put("all", TreeNodeUtils.findRoots(allPermissionCollect));
        // 将当前角色拥有的权限Id，以列表的形式返回
        map.put("have", hashSet);
        return map;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(RoleCanCreateInfo info) {
        if(baseMapper.countByRoleName(info.getRoleName())==1){
            throw new ParameterException("已存在<"+info.getRoleName()+">角色");
        }
        SysRole entity=new SysRole();
        entity.setRoleName(info.getRoleName());
        entity.setDescription(info.getDescription());
        entity.setCreateTime(LocalDateTime.now());
        entity.setLastUpdateTime(LocalDateTime.now());
        this.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(RoleCanModifyInfo info) {
        if(InitData.ROOT_ROLE.equals(info.getRid())){
            throw new ParameterException("不能操作超级管理角色");
        }
        if(baseMapper.selectById(info.getRid())==null){
            throw new ParameterException("无此角色");
        }
        Set<String> users = baseMapper.usersRefRole(info.getRid());
        users.forEach((user)->{tokenStorage().delete(user);});
        baseMapper.updateRole(info);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Long id) {
        if(InitData.ROOT_ROLE.equals(id)){
            throw new ParameterException("不能操作超级管理角色");
        }
        if(baseMapper.selectById(id)==null){
            throw new ParameterException("无此角色");
        }
        if(baseMapper.countUserRef(id)!=0){
            throw new ParameterException("有用户引用此角色");
        }
        baseMapper.deleteHavePermissions(id);
        baseMapper.deleteById(id);
    }

}
